'''
Created on Apr 28, 2011

@author: Bartosz Alchimowicz
'''

# from tfct import screenspec

class FUSE(object):
	def __init__(self, conf):
		self.conf = conf

		assert isinstance(self.conf, dict)
		assert self.conf.has_key('screenspec') == True

		self.use_cases = []

	def add_usecase(self, name, level, id = None):
		if id == None:
			tid = "UC%d" % (len(self.use_cases) + 1)

		t = UseCase(self.conf, tid, name, level)
		self.use_cases.append(t)

		return t

	def get_usecase(self, indx):
		for uc in self.use_cases:
			if uc.get_id() == indx:
				return uc
		return None

	def as_text(self):
		return "\n".join([uc.as_text() for uc in self.use_cases])

class Scenario(object):
	def __init__(self, conf):
		self.conf = conf

		self.steps = []

	def add_step(self, step):
		self.steps.append(step)

	def get_steps(self):
		return self.steps

	def as_text(self):
		return "".join([s.as_text() for s in self.steps])

class UseCase(object):
	def __init__(self, conf, id, name, level):
		self.conf = conf

		self.id = id
		self.name = name
		self.level = level
		self.main_scenarion = Scenario(self.conf)
		self.exceptions = []

	def add_step(self, text, screen_name = None):
		t = Step(self.conf, len(self.main_scenarion.steps) + 1, text, screen_name)
		self.main_scenarion.add_step(t)

		return t

	def __get_excpetion_id(self, step):
		'''
		Compute id for new excpetion.

		@param step reference to an existing step in use case

		For each exception there is a different id. It is expected that
		same step has the same number and different letter.

		Correct examples: 4a, 4b, 5a, 6a
		INcorrect examples: 4a, 4b, 5c, 6d
		'''
		number = 0
		for exception in self.exceptions:
			if exception.step == step:
				number = len(self.exceptions)
				break

		return chr(number + ord('a'))

	def add_exception(self, step, name):
		if isinstance(step, int):
			step = self.main_scenarion.steps[step - 1]
		elif isinstance(step, Step):
			step = self.main_scenarion.steps.index(step)
		else:
			raise Exception("Unsupported step reference")

		t = Exception(self.conf, step, self.__get_excpetion_id(step), name)

		self.exceptions.append(t)

		return t

	def get_id(self):
		return self.id

	def get_step(self, indx):
		steps = self.main_scenarion.get_steps()
		for step in steps:
			if step.get_id() == indx:
				return step
		return None

	def as_text(self):
		result  = "%s: %s\n" % (self.id, self.name)
		result += "Level: %s\n" % (self.level)
		result += "Main scenario:\n"
		result += self.main_scenarion.as_text()

		if len(self.exceptions) != 0:
			result += "Exceptions:\n"
			result += "".join([exception.as_text() for exception in self.exceptions])

		return result

class Exception(object):
	def __init__(self, conf, step, id, name):
		self.conf = conf

		self.step = step
		self.id = id
		self.name = name
		self.scenario = Scenario(self.conf)

	def __get_new_step_id(self):
		return "%s%s%s" % (self.step.id, self.id, len(self.scenario.steps) + 1)

	def add_step(self, text, screen_name = None):
		t = Step(self.conf, self.__get_new_step_id(), text, screen_name)
		self.scenario.add_step(t)

		return t

	def as_text(self):
		result  = "%s%s. %s\n" % (self.step.id, self.id, self.name)
		result += self.scenario.as_text()

		return result

class Step(object):
	def __init__(self, conf, id, text, screen_name = None):
		self.conf = conf

		self.id = id
		self.text = text
		self.screen_name = screen_name

		self.screen = None

		if conf['screenspec'].has_key(screen_name):
			self.screen = conf['screenspec'][screen_name]
		elif screen_name != None:
			# print "\033[31mWARNING: no reference to screen %s\033[0m" % screen_name
			#print "WARNING: no reference to screen %s" % screen_name
			pass

	def get_id(self):
		return self.id

	def get_screen(self):
		return self.screen		

	def as_text(self):
		result = "%s. %s" % (self.id, self.text)

		if self.screen_name:
			result += " [%s]" % self.screen_name

		result += "\n"

		return result
